/**
 * NodePackageLauncher.java
 * ************************** 
 * @date Mar 18, 2011
 * @author Michele Tamburini
 * 
 * **************************
 */
package Launcher;

import gossipServices.aggregation.Aggregation;
import gossipServices.aggregation.AggregationFactory;
import gossipServices.basic.nodeDescriptors.ConcreteNodeDescriptor;
import gossipServices.pss.ConcretePeerSamplingService;
import gossipServices.pss.PeerSamplingService;
import gossipServices.pss.PssFactoryInitializer;
import infrastructureAPI.Service;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Vector;

import networkRmi.CommunicationHandler;
import networkRmi.NetworkManager;
import systems.dispatcher.DispatcherSystem;

/**
 * 
 * Description:
 * This is the main class and the start point to launch a node.
 * The node will try to connect to a node already belonging to the cloud
 * and exchange a subset of the partial view.
 *
 */
public class Main_NodePackage {
	private static String laboratory = "laboratoryMachines.txt";
	private static String localhost = "localhostMachines.txt";
	
	public static NetworkManager networkManager;
	public static PssFactoryInitializer pssFactory = new PssFactoryInitializer();
	private static AggregationFactory aggFactory;
	private static DispatcherSystem dispatcher;
//	private static BootstrapingFactory bootstrapingFactory;
//	private static TManFactory tmanFactory;
	
	private static List<Service> runningServices;
	
	/**
	 * -lab: laboratory.
	 * Launch the node with the view initialization
	 * of Ercolani laboratory at University of Bologna
	 */
	public static final String LAB_PAR = "-lab";
	
	/**
	 * -n : name
	 * The name of the current note (please avoid special characters) 
	 */
	public static final String NAME_PAR = "-n";
	
	/**
	 * -vv : stands for Visualize View.
	 * This option sets the output of the view during the 
	 * PeerSamplingService action.
	 */
	public static final String VIEW_PAR = "-vv";
	
	/**
	 * -h -help : help
	 * Print the help message
	 */
	public static final String HELP_PAR = "-h";
	public static final String HELP_PAR2 = "-help";
	
	/**
	 * -agg : aggregation
	 * Parameter to set the aggregation initial value
	 */
	public static final String AGG_PAR = "-agg";
	
	/**
	 * -enm : Errors Network Manager
	 * ErrorsNetManager: enables the error messages of the 
	 * NetManager. It will notifies each time a message didn't
	 * reach the target
	 */
	public static final String ERR_NM_PAR = "-enm";
	
	/**
	 * 
	 */
	public Main_NodePackage() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		PeerSamplingService pss;
		Aggregation agg;
		String inputViewFile = localhost;
		Vector<String> arguments = new Vector<String>();
		String nodeName = "node";
		
		if(args.length > 0){
			for(int i=0; i<args.length; i++)
				arguments.add(args[i]);
		}
		
		if(arguments.isEmpty() ||arguments.contains(HELP_PAR) 
				|| arguments.contains(HELP_PAR2)){
			showUsage();
		}else{

			try {
				nodeName = InetAddress.getLocalHost().getHostName();
			} catch (UnknownHostException e) {
				e.printStackTrace();
			}

			if(arguments.contains(NAME_PAR)){
				int index = arguments.indexOf(NAME_PAR);
				nodeName = arguments.get(index +1);
			}

			if(arguments.contains(LAB_PAR)){
				inputViewFile = laboratory;
			}
			
			nodeName = ConcreteNodeDescriptor.adjustNodeName(nodeName);
			networkManager = new CommunicationHandler(nodeName);
			pssFactory.initializePss(nodeName, inputViewFile, networkManager);
			pss = pssFactory.getPss();

			if(arguments.contains(ERR_NM_PAR)){
				((CommunicationHandler)networkManager).enableShowErrors();
			}
			
//			Property prop = new Property();
//			prop.prop();
			
			aggFactory = new AggregationFactory(pssFactory.getView(), pss, networkManager);
			if(arguments.contains(AGG_PAR)){
				@SuppressWarnings("unused")
				boolean ret;
				double val = new Double(arguments.get(arguments.indexOf(AGG_PAR) + 1)).doubleValue();
				ret = aggFactory.peakInitializator( nodeName, val);
//				aggFactory = new AggregationFactory(pssFactory.getView(), pss, networkManager, val);
				System.out.println("Setting the node "+ nodeName +"\n " +
						"with the Aggregation value of "+val );
			}
			aggFactory.buildAggregation();
			agg = aggFactory.getAgg();
			
			/*
			 * Build the Dispatcher
			 */
			runningServices = new Vector<Service>();
			runningServices.add(networkManager);
			runningServices.add(pss);
			runningServices.add(agg);
			dispatcher = new DispatcherSystem(networkManager, runningServices);
			
			// The TMan is activate through a request from a user of the cloud
//			tmanFactory = new TManFactory(networkManager, pss);
//			tmanFactory.activateTMan(pss.accessPartialView());
			
			// Parameter to show the view
			boolean showView = false;
			if(arguments.contains(VIEW_PAR))
				showView = true;
			
			((ConcretePeerSamplingService) pss).showView(showView);
			pss.init();
			agg.start();
			dispatcher.start();
			
//			tmanFactory.getTMan().start();
			
		}
		
	}

	/**
	 * 
	 */
	private static void showUsage() {
		print("Welcome to The Cloud System\n");
		print("You can use the following options: \n");
		print(NAME_PAR + " <NAME>: \t to set the name of the current node\n");
		print(LAB_PAR + ": \t to specify that you are launching a node of the " +
				"Ercolani laboratory in Bologna (it will set accordingly the " +
				"initial view);\n");
		print(VIEW_PAR + ": \t to set true the visualization of the PSS view on the screen;\n");
		print(AGG_PAR +" <number>: \t to specify the starting value of the Aggregation service;\n");
		print(ERR_NM_PAR + ": \t to enable the visualization of the NetworkManager errors on the screen;\n");
		print(HELP_PAR + " or " + HELP_PAR2 + ": \t to show this help.\n\n");
	}

	/**
	 * @param string
	 */
	private static void print(String string) {
		System.out.print(string);
	}

}
